#include "L1cache.h"

// 构造函数：初始化缓存参数及统计数据
Cache::Cache(int argc, char* argv[]) 
{
    // 从命令行参数中获取缓存配置
    blockSize = stoul(argv[1]);       // 块大小
    size = stoul(argv[2]);            // 缓存总大小
    associativity = stoul(argv[3]);   // 组相联度
    replace_policy = stoul(argv[4]);  // 替换策略：0为LRU，1为LFU
    write_policy = stoul(argv[5]);    // 写策略：0为WBWA，1为WTNA
    trace_file = string(argv[6]);     // 读取跟踪文件路径

    // 根据缓存大小和组相联度，计算出缓存组数，并初始化缓存
    cache_set.resize(size / (blockSize * associativity));
    for(unsigned i = 0; i< cache_set.size(); i++) 
        cache_set[i].second.resize(associativity);   // 初始化每组的缓存块
    
    // 初始化统计数据
    totalReads = missReads = totalWrites = missWrites = writeBack = 0;
}

// 运行模拟器：从跟踪文件中读取操作并执行访问
void Cache::Run() {
    ifstream file_path("../traces/" + trace_file);   // 打开跟踪文件
    string mid;
    while(getline(file_path, mid)){                  // 逐行读取操作
        char r_or_w;                                 // 读写操作标识符
        unsigned address;                            // 访问地址
        istringstream is(mid);
        is >> r_or_w;                                // 获取操作类型（'r' 或 'w'）
        is >> hex >> address;                        // 获取16进制地址

        // 计算地址的tag和index
        unsigned tag = address / (blockSize * cache_set.size());
        unsigned index = (address ^ (tag * blockSize * cache_set.size())) / blockSize;

        // 执行缓存访问
        Visit(addr(tag, index), r_or_w);             
    }
    file_path.close();                               // 关闭跟踪文件
    PrintResult();                                   // 输出最终结果
}

// 访问缓存：根据替换策略和写策略处理缓存块访问
void Cache::Visit(addr address, char op) {
    // 更新读写操作统计
    op=='r' ? totalReads++ : totalWrites++;
    
    // 遍历对应组内的缓存块，检查是否命中
    for(unsigned i=0;i<cache_set[address.second].second.size();i++) 
        if(cache_set[address.second].second[i].valid && 
           (cache_set[address.second].second[i].tag == address.first)) {    // 如果命中
            
            // LRU 替换策略：更新使用计数
            if(!replace_policy){     
                unsigned find_countBlock = cache_set[address.second].second[i].countBlock;
                vector<Block>::iterator mid;
                for(mid = cache_set[address.second].second.begin(); mid != cache_set[address.second].second.end(); mid++)
                    mid->countBlock += (mid->valid && mid->countBlock < find_countBlock);  // 增加旧块计数      
                cache_set[address.second].second[i].countBlock = 0;  // 当前块的计数置0
            }
            // LFU 替换策略：增加访问次数
            else                
                cache_set[address.second].second[i].countBlock++;

            // 写操作时，设置脏位
            cache_set[address.second].second[i].dirty |= (op == 'w' && !write_policy);   
            return;
        }

    // 如果是写操作且采用写直达，则不执行替换
    if(op == 'w' && write_policy)    
        missWrites++;   // 统计写缺失
    else 
        Replace(address, op);  // 否则执行替换
}

// 替换缓存块：选择受害者块进行替换
void Cache::Replace(addr address, char op){
    // 更新读写缺失统计
    op == 'r' ? missReads++ : missWrites++;

    // 查找空闲块，优先替换无效块
    vector<Block>::iterator victim;             
    for(victim = cache_set[address.second].second.begin(); victim != cache_set[address.second].second.end(); ++victim)    
        if(!victim->valid)
            break;

    // 如果没有找到无效块，则根据替换策略选择受害者块
    if(victim == cache_set[address.second].second.end()){     
        if(replace_policy)  // LFU 策略：选择最少使用块
            victim = min_element(cache_set[address.second].second.begin(), cache_set[address.second].second.end());
        else  // LRU 策略：选择最长未使用块
            victim = max_element(cache_set[address.second].second.begin(), cache_set[address.second].second.end());
    }

    // 如果受害者块有效且是脏块，则需要写回
    if(victim->valid && victim->dirty)        
        writeBack++;

    // 根据替换策略更新缓存块
    if(replace_policy){  // LFU 替换
        if(victim->valid)
            cache_set[address.second].first = victim->countBlock;  
        *victim = {cache_set[address.second].first + 1, address.first, op=='w', true};  // 更新块信息
    }
    else{  // LRU 替换
        *victim = {0, address.first, op=='w', true};  // 更新块信息
        for(vector<Block>::iterator i = cache_set[address.second].second.begin(); i != cache_set[address.second].second.end(); i++)
            if(i->valid && i != victim) 
                i->countBlock++;  // 更新其他块的计数               
    }
}

// 打印模拟结果
void Cache::PrintResult(){
    // 打印缓存配置信息
    cout << "  ===== Simulator configuration =====\n";
    cout << "  L1_BLOCKSIZE:" << setw(22) << blockSize << endl;
    cout << "  L1_SIZE:" << setw(27) << size << endl;
    cout << "  L1_ASSOC:" << setw(26) << associativity << endl;
    cout << "  L1_REPLACEMENT_POLICY:" << setw(13) << replace_policy << endl;
    cout << "  L1_WRITE_POLICY:" << setw(19) << write_policy << endl;
    cout << "  trace_file:" << setw(24) << trace_file << endl;
    cout << "  ===================================\n\n";

    // 打印缓存内容
    cout << "===== L1 contents =====\n";
    for(unsigned i = 0; i != cache_set.size(); i++){
        cout << "set" << setw(4) << i << ":";
        vector<Block> mid = cache_set[i].second;
        for(unsigned j = 0; j < mid.size(); j++)
            cout << hex << setw(8) << mid[j].tag << ' ' << ((!write_policy && mid[j].dirty) ? 'D' : ' ');
        cout << endl << dec;
    }

    // 计算并打印模拟结果
    float HT, MR, MP;
    HT = 0.25 + 2.5 * (size / (512.0 * 1024)) + 0.025 * (blockSize / 16.0) + 0.025 * associativity;  // 访问时间公式
    MR = (missReads + missWrites) / (float)(totalReads + totalWrites);  // 缺失率
    MP = 20 + 0.5 * (blockSize / 16.0);  // 内存惩罚时间
    cout << "\n  ====== Simulation results (raw) ======\n";
    cout << "  a. number of L1 reads:" << setw(16) << totalReads << endl;
    cout << "  b. number of L1 read misses:" << setw(10) << missReads << endl;
    cout << "  c. number of L1 writes:" << setw(15) << totalWrites << endl;
    cout << "  d. number of L1 write misses:" << setw(9) << missWrites << endl;
    cout << "  e. L1 miss rate:" << setw(22) << fixed << setprecision(4) << MR << endl;
    cout << "  f. number of writebacks from L1:" << setw(6) << writeBack << endl;
    cout << "  g. total memory traffic:" << setw(14) << ((write_policy) ? 
        (missReads + totalWrites) : (missReads + missWrites + writeBack)) << endl;

    // 打印性能结果
    cout << "\n  ==== Simulation results (performance) ====\n";
    cout << "  1. average access time:" << setw(15) << HT + MR * MP << " ns";
}
